package Test;

import static org.junit.Assert.*;
import interfaces.Pointer;
import interfaces.PointerOffsetGenerator;
import interfaces.PointerReader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.junit.Before;
import org.junit.Test;

import Pointers.JPointerFactory;
import Pointers.OffsetRangeGenerator;
import Pointers.JPointerFactory.PointerType;
import Script.JPointerReader;
import Script.Offset;

public class PointerReaderTest {
	File gamefile;
	
	@Before
	public void setup() {
		
		/* Original unaltered file. */
		gamefile = new File("testFiles/gameTest/FFIII_original.smc");
	}
	
	@Test
	public void canReadSinglePointer() throws FileNotFoundException, IOException {
		JPointerFactory factory = 
						new JPointerFactory(PointerType._2Byte_littleEndian);
		
		// In spot 845942 is 9E0B
		PointerOffsetGenerator gen = new OffsetRangeGenerator(new Offset(845942), 
															new Offset(845944), 
															2, 0);
		ArrayList<Offset> offList = gen.getOffsets();
		PointerReader reader = new JPointerReader(gamefile, offList, factory);
		HashMap<Integer, Pointer> pList = reader.getPointers();
		
		// 40459 = 9E0B, 0B9E = 2974
		assertEquals(new Long(pList.get(1).getValue()), new Long(2974));
		
	}
	
	/**
	 * Attempts to read 4 consecutive bytes.
	 * 
	 * 9E 0B B0 0B
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	@Test
	public void canReadTwoSubsequentPointers() throws FileNotFoundException, IOException {
		JPointerFactory factory = 
			new JPointerFactory(PointerType._2Byte_littleEndian);
		PointerOffsetGenerator gen = new OffsetRangeGenerator(new Offset(845942), 
															new Offset(845946), 
															2, 0);
		ArrayList<Offset> offList = gen.getOffsets();
		PointerReader reader = new JPointerReader(gamefile, offList, factory);
		HashMap<Integer, Pointer> pList = reader.getPointers();
		
		// 40459 = 9E0B, 0B9E = 2974
		assertEquals(new Long(pList.get(1).getValue()), new Long(2974));
		
		// 45067 = 11D7, D711 = 4567
		assertEquals(new Long(pList.get(2).getValue()), new Long(2992));

	}
	
	/**
	 * Attempts to read 4 consecutive bytes with 3 bytes spacing.
	 * 
	 * 9E 0B _ _ _ 0B E9
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 * @throws IOException 
	 * @throws FileNotFoundException 
	 */
	@Test
	public void canReadTwoSubsequentPointersWithSpacing() throws FileNotFoundException, IOException {
		JPointerFactory factory = 
			new JPointerFactory(PointerType._2Byte_littleEndian);
		PointerOffsetGenerator gen = new OffsetRangeGenerator(new Offset(845942), 
															new Offset(845949), 
															2, 3);
		ArrayList<Offset> offList = gen.getOffsets();
		PointerReader reader = new JPointerReader(gamefile, offList, factory);
		HashMap<Integer, Pointer> pList = reader.getPointers();
		
		// 40459 = 9E0B, 0B9E = 2974
		assertEquals(new Long(pList.get(1).getValue()), new Long(2974));
		
		// 3049 = 0BE9, E90B = 59659
		assertEquals(new Long(pList.get(2).getValue()), new Long(59659));
	}
	
	@Test
	public void canReadThreeSubsequentPointersWithSpacing() throws FileNotFoundException, IOException {
		JPointerFactory factory = 
			new JPointerFactory(PointerType._2Byte_littleEndian);
		PointerOffsetGenerator gen = new OffsetRangeGenerator(new Offset(845942), 
															new Offset(845950), 
															2, 1);
		ArrayList<Offset> offList = gen.getOffsets();
		PointerReader reader = new JPointerReader(gamefile, offList, factory);
		HashMap<Integer, Pointer> pList = reader.getPointers();
		
		// 40459 = 9E0B, 0B9E = 2974
		assertEquals(new Long(pList.get(1).getValue()), new Long(2974));
		
		// 3013 = 0BC5, C50B = 50443
		assertEquals(new Long(pList.get(2).getValue()), new Long(50443));
		
		// 59659 = E90B, 0BE9 = 3049
		assertEquals(new Long(pList.get(3).getValue()), new Long(3049));
	}
	
	/* Validation */
	
	@Test
	public void invalidatedOverlappingPointerValues() {
		JPointerFactory factory = 
			new JPointerFactory(PointerType._2Byte_littleEndian);
		ArrayList<Offset> offList = new ArrayList<Offset>();
		
		/* Add two overlapping offsets, assuming pointersize 2. */
		offList.add(new Offset(5));
		offList.add(new Offset(6));
		
		PointerReader reader = new JPointerReader(gamefile, offList, factory);
		
		assertFalse(reader.isValid().size() == 0);
	}
	
	@Test
	public void sortsValues() {
		JPointerFactory factory = 
			new JPointerFactory(PointerType._2Byte_littleEndian);
		ArrayList<Offset> offList = new ArrayList<Offset>();
		
		/* Add two offsets in the wrong order, assuming pointersize 2. */
		offList.add(new Offset(9));
		offList.add(new Offset(5));
		
		PointerReader reader = new JPointerReader(gamefile, offList, factory);
		
		/* Should still validate, since the constructor sorts them. */
		assertEquals(reader.isValid().size(), 0);
	}

}
